package com.mcc.myapplication

fun double(x: Int): Int {
    return 2 * x
}

fun powerOf(number: Int, exponent: Int): Int {
    /*……*/
    return 0
}

fun powerOf2(
    number: Int,
    exponent: Int, // 尾部逗号
) {
    /*……*/
}

fun read(
    b: ByteArray,
    off: Int = 0,
    len: Int = b.size,
) {
    /*……*/
}

fun foo(
    bar: Int = 0,
    baz: Int,
) {
    println("bar=$bar,baz=$baz")
    val x = bar + baz
}

// 如果在默认参数之后的最后一个参数是 lambda 表达式，那么它既可以作为具名参数在括号内传入，也可以在括号外传入
fun foo(
    bar: Int = 0,
    baz: Int = 1,
    qux: () -> Unit,
) {
    println("bar=$bar,baz=$baz")
    qux()
}

fun hello() {
    println("hello fun")
}

// 可以通过具名参数和展开操作符来传入可变参数（vararg）：
fun foo(vararg strings: String) {
    strings.asList().forEach { print("$it ") }
}

// 返回 Unit 的函数
fun printHello(name: String?): Unit {}
fun printHello2(name: String?) {}

// 单表达式函数
// 当函数体由单个表达式构成时，可以省略花括号并且在 = 符号之后指定代码体即可
fun double2(x: Int): Int = x * 2
fun double3(x: Int) = x * 2 // 返回值类型可由编译器推断

// 具有块代码体的函数必须始终显式指定返回类型，除非他们旨在返回 Unit
// Kotlin 不推断具有块代码体的函数的返回类型

// 可变数量的参数（varargs）
fun <T> asList(vararg ts: T): List<T> {
    val result = ArrayList<T>()
    for (t in ts) // ts 是一个数组
        result.add(t)
    return result
}

/**
 * 中缀表示法
 * 它们必须是成员函数或扩展函数。
 * 它们必须只有一个参数。
 * 其参数不得接受可变数量的参数且不能有默认值。
 */
infix fun Int.shl2(x: Int): Int {
    return this - x
}

// Kotlin 支持局部函数，即一个函数在另一个函数内部
fun fabs(n: Int): Long {
    val numbersMap = mutableMapOf(1 to 1L, 2 to 1L)
    fun impl(x: Int = 1): Long {
        if (x < 1) return 0
        if (x < 3) return 1
        var v = numbersMap[x - 1]
        if (v == null) {
            v = impl(x - 1)
            numbersMap[x - 1] = v
        }
        val w: Long? = numbersMap[x - 2]
        return v + w!!
    }
    return impl(n)
}

fun main() {
    println(fabs(123))
}

fun main2() {
//    foo(baz = 100)
    foo(1) { println("hello $") }     // 使用默认值 baz = 1
    foo(qux = { println("hello 2") }) // 使用两个默认值 bar = 0 与 baz = 1
    foo { println("hello 3") }        // 使用两个默认值 bar = 0 与 baz = 1
    foo(qux = { hello() })

    // 可变参数
    foo(strings = *arrayOf("a", "b", "c"))

    val a = intArrayOf(1, 2, 3) // IntArray 是一种原生类型数组
    val list = asList(-1, 0, *a.toTypedArray(), 4)
    list.joinToString().also(::println)

    println(3.shl2(5))
    println(3 shl2 5) // 中缀表示法（忽略该调用的点与圆括号）调用

    println(fabs(123))
}